#include <vector_types.h>

#include <algorithm/analytical_model/algorithm/cuda/SimplifiedMethod.cuh>
#include <algorithm/analytical_model/algorithm/cuda/inter_op/SimplifiedMethod.h>
#include <utils/Utils.h>

#include <bit>

using namespace solar::cuda::inter_op;

SimplifiedMethod::SimplifiedMethod(Float3* helio_vertices, Float3* recv_vertices,
                                   Float3 helio_normal, Float3 recv_normal, Float3 helio_pos,
                                   Float3 target_center, Float3 helio_size, Int2 row_col, float DNI,
                                   cudaStream_t stream)
{
    auto* helio_vertices_ptr = std::bit_cast<float3*>(helio_vertices);
    auto* recv_vertices_ptr = std::bit_cast<float3*>(recv_vertices);
    this->delegate_ptr_ = std::make_shared<::solar::cuda::SimplifiedMethod>(
        helio_vertices_ptr, recv_vertices_ptr, structCopy<float3>(helio_normal),
        structCopy<float3>(recv_normal), structCopy<float3>(helio_pos),
        structCopy<float3>(target_center), structCopy<float3>(helio_size),
        structCopy<int2>(row_col), DNI, stream);
}

SimplifiedMethod::SimplifiedMethod(Float3* helio_vertices, Float3 recv_size, Float3 helio_normal,
                                   Float3 recv_pos, Float3 helio_pos, Float3 target_center,
                                   Float3 helio_size, Int2 row_col, float DNI, float* d_array,
                                   cudaStream_t stream)
{
    auto* helio_vertices_ptr = std::bit_cast<float3*>(helio_vertices);
    this->delegate_ptr_ = std::make_shared<::solar::cuda::SimplifiedMethod>(
        helio_vertices_ptr, structCopy<float3>(recv_size), structCopy<float3>(helio_normal),
        structCopy<float3>(recv_pos), structCopy<float3>(helio_pos),
        structCopy<float3>(target_center), structCopy<float3>(helio_size),
        structCopy<int2>(row_col), DNI, d_array, stream);
}

SimplifiedMethod::SimplifiedMethod(Float3* d_image_plane_x_z_axes, Float4* d_center_bias,
                                   Float3* d_flux_params, int n, Float3 recv_size, Float3 recv_pos,
                                   Int2 row_col, cudaStream_t stream)
{
    auto* image_plane_x_z_axes_ptr = std::bit_cast<float3*>(d_image_plane_x_z_axes);
    auto* center_bias_ptr = std::bit_cast<float4*>(d_center_bias);
    auto* flux_params_ptr = std::bit_cast<float3*>(d_flux_params);
    this->delegate_ptr_ = std::make_shared<::solar::cuda::SimplifiedMethod>(
        image_plane_x_z_axes_ptr, center_bias_ptr, flux_params_ptr, n,
        structCopy<float3>(recv_size), structCopy<float3>(recv_pos), structCopy<int2>(row_col),
        stream);
}

void SimplifiedMethod::drawFluxMap() const { this->delegate_ptr_->drawFluxMap(); }

void SimplifiedMethod::drawFluxMapCylinder() const { this->delegate_ptr_->drawFluxMapCylinder(); }

void SimplifiedMethod::setHelioVertices(Float3* helio_vertices) const
{
    auto* helio_vertices_ptr = std::bit_cast<float3*>(helio_vertices);
    this->delegate_ptr_->setHelioVertices(helio_vertices_ptr);
}

void SimplifiedMethod::setRecvVertices(Float3* recv_vertices) const
{
    auto* recv_vertices_ptr = std::bit_cast<float3*>(recv_vertices);
    this->delegate_ptr_->setRecvVertices(recv_vertices_ptr);
}

auto SimplifiedMethod::getFluxMap() const -> float* { return this->delegate_ptr_->d_array_; }

auto SimplifiedMethod::loadNormalDistributionArray() const -> bool
{
    return this->delegate_ptr_->loadNormalDistributionArray();
}

void SimplifiedMethod::setModelParams(float sigma1, float sigma2, float peak,
                                      float correlation) const
{
    this->delegate_ptr_->sigma1_ = sigma1;
    this->delegate_ptr_->sigma2_ = sigma2;
    this->delegate_ptr_->peak_ = peak;
    this->delegate_ptr_->correlation_ = correlation;
}

void SimplifiedMethod::setCenterBias(const Float3& bias) const
{
    structCopy(bias, this->delegate_ptr_->center_bias_);
}

void SimplifiedMethod::setShadowBlockFactor(float factor) const
{
    this->delegate_ptr_->shadow_block_factor_ = factor;
}

auto SimplifiedMethod::getCudaStream() const -> cudaStream_t
{
    return this->delegate_ptr_->stream_;
}

void SimplifiedMethod::setCudaStream(const cudaStream_t& stream) const
{
    this->delegate_ptr_->setCudaStream(stream);
}

void SimplifiedMethod::fakeClearResult() const { this->delegate_ptr_->d_array_ = nullptr; }

void SimplifiedMethod::fakeClearCudaStream() const { this->delegate_ptr_->stream_ = nullptr; }
